/*
 * TCU 与 青莲云 规约 接口实现 
 *
 */
#include "common.h"
#include "charge_os.h"
#include "charge_user.h"
#include "charge.h"
#include "ql_main_interface.h"
#include "app_debug_ql.h"
#include "qlcloud_client.h"

static os_thread_t _thread_update;
#define LEN 16

#define METER_IN CHARGE_GUN_CNT

// 主控传过来的配置参数 
ql_para_form_main  gt_para_from_main = {0};

// 遥信值（can口传递过来的）
extern out_yx yxdata[CHARGE_GUN_CNT];

// 遥测值（can口传递过来的）
extern union u_out_mx ycdata[CHARGE_GUN_CNT];

extern int g_can_state[CHARGE_GUN_CNT];

// 启动充电信息
extern start_mx g_startInfo[CHARGE_GUN_CNT];

// 充电参数
extern Charge_Arg g_chargepara_ql[CHARGE_GUN_CNT];

// 停止充电信息
extern end_mx g_stopInfo[CHARGE_GUN_CNT];

// 电表实时数据
extern MeterDataReal g_realmtData[CHARGE_GUN_CNT+1];

// 读取的最后充电功率
extern u32 last_kWh[];

// 设备充电状态
extern int g_charge_state[];

extern MeterData_ql g_mtData[CHARGE_GUN_CNT];

 void charge_init_param(ql_para_form_main *pConfig)
 {
     int i = 0;
 
     memset(&g_user_pile, 0, sizeof(user_pile_t));
     memset(&g_user_gun[0], 0, sizeof(user_gun_t)*CHARGE_GUN_CNT);
     memset(&g_user_bms[0], 0, sizeof(user_bms_t)*CHARGE_GUN_CNT);
 
     //充电桩硬件参数赋值
     g_user_pile.rated_voltage = pConfig->rated_v;//convert_electric(100.9);
     g_user_pile.rated_current = pConfig->rated_i;
     g_user_pile.max_voltage = pConfig->max_v;
     g_user_pile.max_current = pConfig->max_i;
     g_user_pile.max_power = pConfig->max_power;
     g_user_pile.min_power = pConfig->min_power;
     g_user_pile.rated_power = pConfig->rated_power;
     g_user_pile.temperature = convert_temperature(30);
     g_user_pile.humidity = 20;
 
     for (i = 0; i < CHARGE_GUN_CNT; i++)
     {
         //为地锁ID赋值
         g_user_lock[i].id = i + 1;
     }
 }

 void *update_gun_data(void *param)
 {
     int i = 0;
 
     while (1)
     {
         for (i = 1; i < CHARGE_GUN_CNT + 1; i++)
         {
             if (charge_get_gun_state(i) == GUN_STATE_CHARGING)
             {
                 user_update_gun_data(i);
                 user_update_bms_charging(i);
             }
         }
         sleep(1);
     }
 }
 
 int initTaskClientQL()
 {
     char str[LEN] = {0x00,};
 
     charge_init_param(&gt_para_from_main);
     charge_run(&g_user_pile, &g_user_gun[0], &g_user_bms[0], &g_user_lock[0]);
 
     if (os_thread_create("updater", &_thread_update, update_gun_data, NULL, os_priority_Low, CHARGE_THREAD_STACK_SIZE) != 0)
     {
         log_error("pthread_create error\r\n");
         return -1;
     }
 }

// 初始化与青莲云通讯任务，初始化参数 
int initQlCloud(void *pxj)
{
    // 获取主控传过来的配置数据 
    if (pxj != NULL)
    {
        gt_para_from_main = *(ql_para_form_main*)pxj;
    }
    
    printf("\r\n\r\n 主控调用青莲云客户端动态库！\r\n gunnum=%d  mod=%d tcuname=%s\r\n", gt_para_from_main.gunnum, gt_para_from_main.charge_mode_num, gt_para_from_main.devNo);
    printf("server:%s, port:%d",gt_para_from_main.server_ip, gt_para_from_main.server_port);
    printf("\r\n ID:%s, Token:%s", gt_para_from_main.interface_id, gt_para_from_main.token);
	initTaskClientQL();
    
    return 0;
}




static int ql_updateYX_DC(u8 gunid, void *p_data)
{
    u8 b0, b1, b2;
    out_yx *pyxdata = (out_yx *) p_data;
    int i;
    u8 mark_pf22[]={0xff,0xff,0xff,0xff,0xff,0xff,0x03,0};  
    u8 temp22_1[8];
    u8 temp22_2[8];
    static u8 init_flag_pf22[8] = {0};
    static u8 init_flag_pf23[8] = {0};

    debug_mdata("上次 gunid=%d  pf22=%.*a  pf23=%.*a", gunid, 8, yxdata[gunid].yx_dc_pf22, 8, yxdata[gunid].yx_dc_pf23);
    debug_mdata("本次 gunid=%d  pf22=%.*a  pf23=%.*a", gunid, 8, pyxdata->yx_dc_pf22, 8, pyxdata->yx_dc_pf23);
    
    memcpy(temp22_1, yxdata[gunid].yx_dc_pf22, 8);  // 上一次读取数据 
    memcpy(temp22_2, pyxdata->yx_dc_pf22, 8);       // 更新数据 
    
    for (i = 0; i < 8; i++)
    {
        temp22_1[i] &= mark_pf22[i];
        temp22_2[i] &= mark_pf22[i];
    }
    
    b0 = memcmp(yxdata[gunid].yx_dc_pf22,  pyxdata->yx_dc_pf22, 8);
    b1 = memcmp(temp22_1, temp22_2, 8);  // 屏蔽不使用的BIT 
    b2 = memcmp(yxdata[gunid].yx_dc_pf23, pyxdata->yx_dc_pf23, 8);
    
    if (b1 || (init_flag_pf22[gunid] == 0))
    {
        debug_mdata1("上次上报后摇信变化pf22  temp22_1=%.*a  temp22_2=%.*a",8,temp22_1,8,temp22_2);
        if (b0 || (init_flag_pf22[gunid] == 0))
        {
            ql_memcmpyx_dc_22(gunid,yxdata[gunid].yx_dc_pf22, pyxdata->yx_dc_pf22);
            memcpy(yxdata[gunid].yx_dc_pf22, pyxdata->yx_dc_pf22, 8);
            init_flag_pf22[gunid] = 1;
        }
    }
    else
    {
        debug_mdata("上次上报后摇信没有变化pf22  temp22_1=%.*a  temp22_2=%.*a", 8, temp22_1, 8, temp22_2);
    }
    
    if (b2 || (init_flag_pf23[gunid] == 0))
    {
        debug_mdata1("111上次上报后摇信变化pf23  %.*a  %.*a", 8, yxdata[gunid].yx_dc_pf23, 8, pyxdata->yx_dc_pf23);
        ql_memcmpyx_dc_23(gunid, yxdata[gunid].yx_dc_pf23, pyxdata->yx_dc_pf23);
        memcpy(yxdata[gunid].yx_dc_pf23, pyxdata->yx_dc_pf23, 8);
        init_flag_pf23[gunid] = 1;
    }
    
    if (b1 || b2)
    {
        debug_mdata("\r\n上次上报后摇信变化 gunid=%d ",gunid);
    } 
    else 
    {
        debug_mdata("\r\n上次上报后摇信没有变化gunid=%d ",gunid);
    }

	return 0;
}

static int ql_updateYX_AC(u8 gunid, void *p_data)
{
	u8 b0;
	static u8 flag_first[] = { 1, 1 };
	out_yx *pyxdata = (out_yx *) p_data;

	debug_mdata("上次 gunid=%d  pf32=%.*a", gunid, 8,yxdata[gunid].yx_ac_pf32);
	debug_mdata("本次 gunid=%d  pf32=%.*a", gunid, 8,pyxdata->yx_ac_pf32);

	b0 = memcmp(yxdata[gunid].yx_ac_pf32,  pyxdata->yx_ac_pf32, 8);

	if (b0)
	{
	      debug_mdata("上次上报后摇信变化");
		   memcpy(yxdata[gunid].yx_ac_pf32, pyxdata->yx_ac_pf32, 8);
	}
	else
	{
		debug_mdata("上次上报后摇信没有变化");
	}

	if (flag_first[gunid] == 1) {
		flag_first[gunid] = 0;
	} else {

		if (b0){
			debug_mdata("\r\n上次上报后摇信变化 gunid=%d ",gunid);
		} else {
			debug_mdata("\r\n上次上报后摇信没有变化gunid=%d ",gunid);
		}
	}
	return 0;
}

// 更新遥信处理 
int QL_updateYX(u8 gunid, void *p_data)
{
	static u8 flag_first[]={1, 1};
    main_yx *ptemp=(main_yx *)p_data;
	t_operate_reason op_reason = {0};
    cmdlist  cmd;
    u8 upload_err_flag = 0;

	if (flag_first[gunid] == 1) 
    {
		g_can_state[gunid] = ptemp->errcode;    // 上电初始化 
		flag_first[gunid] = 0;
		if ((g_can_state[gunid] & 0x07) > 0)
		{
			charge_fault_occur(gunid + 1, DEV_ERR_3032);	// 计费单元通讯故障
			upload_err_flag = 1;
		}
	} 
    else 
    {
        if (gunid == 1)
        {
		    printf("打印故障情况  ptemp->errcode=%d   g_can_state[gunid]=%d  \r\n ",ptemp->errcode,       g_can_state[gunid]);
        }
        
		if ((ptemp->errcode&0x07) != (g_can_state[gunid]&0x07)) 
        {
			if (ptemp->errcode & 0x07)
			{
				charge_fault_occur(gunid + 1, DEV_ERR_3032);	// 计费单元通讯故障
				upload_err_flag = 1;
			}
			else if (g_realmtData[gunid].failReadMt == 0)   // 电表无故障
			{
				charge_fault_recover(gunid + 1);
			}
		}
        
		g_can_state[gunid] = ptemp->errcode;
	}

   	debug_mdata("记录来自枪号%d的遥信数据 ",gunid);
    
	if (gt_para_from_main.type == ql_gun_type_dc)
	{
		ql_updateYX_DC(gunid,(void*)&ptemp->yx_data);
	}
	else if (gt_para_from_main.type == ql_gun_type_ac)
	{
		ql_updateYX_AC(gunid,(void*)&ptemp->yx_data);
	}

    if (upload_err_flag > 0)
    {
    	op_reason.detail_code = DEV_ERR_3032;
		op_reason.reason = 5;
		op_reason.gun_id = gunid;
		// 设置故障信息
		cmd.cmdtype = SET_STOP_DETAIL_REASON;
		cmd.body	= (void*)&op_reason;
		gt_para_from_main.cmd_fun(&cmd);
    }
    
	return 0;

}
 
// 更新遥测处理 
int QL_updateYC(u8 gunid, void *p_data)
{
    ycdata[gunid]=*(union u_out_mx*)p_data;
    
   	printf("QL_updateYC记录来自枪号%x的遥测数据  soc=%d\r\n", gunid, (int)ycdata[gunid].dc.MX[2]);

    // 遥测数据更新信息 
    user_update_gun_data_by_yc(gunid + 1, p_data);
    
   	return 0;

}

int QL_finStartCharge(u8 gunid,void* pdata)
{
	StartInfo *p=(StartInfo *)pdata;
    
   	g_startInfo[gunid]=*p->p_startInfo; // 启动是设备状态信息 
    
	if (p->p_chargepara!= NULL && p->p_chargepara[gunid].startmode == 0)    // 刷卡启动
	{
     	g_chargepara_ql[gunid]=*p->p_chargepara;
	}
	Finish_start_charge(gunid);// 20210701 add by cz
	/*if (g_startInfo[gunid].MX2 == 1 || g_startInfo[gunid].MX2 == 0 || g_startInfo[gunid].MX2 == 2)
       	Finish_start_charge(gunid);
	else
		Finish_stop_charge(gunid,1);*/
	return 0;
}

int QL_finStopCharge(u8 gunid,void* pdata)
{
	g_stopInfo[gunid]=*(end_mx *)pdata;
    
	Finish_stop_charge(gunid, 0);   // 停止充电 
    
	return 0;
}


// 更新电表数据处理 
extern u8 g_update_bill_flag[CHARGE_GUN_CNT];

int QL_updateMtData(u8 gunid, void* pdata)
{
	MeterData_ql *preal = (MeterData_ql *)pdata;
    u32 dt;
    static u8  flag_first[] = {1, 1};
    static int flag_err[]  = {0, 0};
    int ret = 0;
    MeterData_ql real = *preal;
    fee_t  fee;
    u32 which_price; //2021-6-18
    //if ( g_realmtData[gunid].failReadMt != real.failReadMt)
    {
        //printf("电表故障%d发生故障，申请上传g_realmtData[gunid].failReadMt=%d\n", gunid, g_realmtData[gunid].failReadMt);
        // addtolink(gunid, (char*)"300d", g_realmtData[gunid].failReadMt);
    }
    
	g_mtData[gunid] = real;
    //      debug_mdata("11收到%d块表 抄表结果  电压：%d  电流:%d  电量:%d  err=%d",gunid,
    //      g_104_realData[gunid].voltage[0], g_104_realData[gunid].current[0], g_104_realData[gunid].kWh[0],g_104_realData[gunid].failReadMt);
    
    if (gunid == METER_IN)
    {
        return 0;
    }
    
    if (g_realmtData[gunid].failReadMt == 1) 
    {
        flag_err[gunid]++;
        printf("gunid=%d 电表故障", gunid);
        if (flag_err[gunid]==1)
        {
            if (gunid == 0)
            {
                printf("电表故障0发生故障，申请上传");
            }
            else
            {
                printf("电表故障1发生故障，申请上传");
            }
        }
    } 
    else 
    {
        flag_err[gunid] = 0;
        
        if (flag_first[gunid] == 1) 
        {
            last_kWh[gunid] = real.kWhEnd[0];  // 上电
            flag_first[gunid] = 0;
        } 
        else 
        {
            dt = real.kWhEnd[0] - last_kWh[gunid];

            // 充电度数大于0.1度，上报 
            if (dt > 10 && g_charge_state[gunid] == CHARGING)////g_104_realData[gunid].kWh[0]
            {
//              printf(
//                      "上次上报后电量变化超过0.1  上报数据 real.kWh[0]=%d last_kWh=%dg_flag_MSG=%x gunid=%d\r\n",
//                      (int) real.kWh[0], (int) last_kWh[gunid], g_flag_MSG,
//                      gunid);
//              if (gunid == 0)
//                  g_flag_MSG |= _MSG_UP_DATA_;
//              else
//                  g_flag_MSG |= _MSG_UP_DATA_1_;

//              printf(
//                      "111上次上报后电量变化超过0.1  上报数据 real.kWh[0]=%d last_kWh=%d g_flag_MSG=%x gunid=%d\r\n",
//                      (int) real.kWh[0], (int) last_kWh[gunid], g_flag_MSG,
//                      gunid);
                ret = 1;
            } 
            else 
            {
//              if(gunid==0)
//              {
//                 if( (g_flag_MSG & _MSG_UP_DATA_)!=0)
//                      g_flag_MSG &= ~_MSG_UP_DATA_;
//
//              }
//              else
//              {
//                  if ( (g_flag_MSG & _MSG_UP_DATA_1_)!=0)
//                      g_flag_MSG &= ~_MSG_UP_DATA_1_;
//
//              }
    
//              debug_mdata(
//                      "上次上报后电量变化不到0.1  上报数据 real.kWh[0]=%d last_kWh=%dg_flag_MSG=%d\r\n",
//                      (int )real.kWh[0], (int )last_kWh[gunid], g_flag_MSG);
            }
        }
    }

    // 充电时才更新费用、计时信息，其他时间不更新 2021-07-05 zh
    // 結束訂單時不更新
    if ((GUN_STATE_CHARGING == charge_get_gun_state(gunid + 1)) && (g_update_bill_flag[gunid] == 0))
    {
        // 将装置计费数据导出到主程序中 
        get_gun_fee(gunid, &fee);
        // 数据输出 
        preal->gun_id = gunid;
        preal->cost_elec = fee.total_fee_elec;
        preal->cost_server = fee.total_fee_service;
        preal->charge_duration = (os_get_time() - fee.start_time);  //单位：s//20210619  fee.total_time;
        debug_ql("set charge duration: %u", preal->charge_duration);
        preal->curkWh[0] = fee.total_kwh;
        preal->rateid = time_get_period();
        //2021-6-18 add by cz
        which_price = fee.price_info.period[preal->rateid] & 0x03;//当前时段采用尖、高、平、谷哪种费率
      	preal->cur_elec = fee.price_info.price_elec[which_price];//当前电费费率是多少

      	which_price = (fee.price_info.period[preal->rateid] & 0x0C) >> 2;
      	preal->cur_servicer = fee.price_info.price_service[which_price];
      	ret = 2;
    }

    return ret;
}
 
// 
int QL_updateMtDataReal(u8 gunid, void* pdata)
{
	MeterDataReal *pmeter = ( MeterDataReal *)pdata;
	static u8 commFail[CHARGE_GUN_CNT] = {0};
	static u8 fail_cnt[CHARGE_GUN_CNT] = {0};
	static u8 upload[CHARGE_GUN_CNT] = {0};
	t_operate_reason op_reason = {0};
    cmdlist  cmd;

	if (pmeter->failReadMt == 0)
	{
		g_realmtData[gunid] = *pmeter;
	}

	debug_mdata("QL: gun:%d, kwh:%d data:%d fail:%d", gunid, g_realmtData[gunid].kWh[0], pmeter->kWh[0], pmeter->failReadMt);
	if (pmeter->failReadMt != commFail[gunid])
	{
		if (pmeter->failReadMt)
		{
			fail_cnt[gunid] = 1;
	    	if (fail_cnt[gunid] > 0) // 连续接收错误1次认为有误
	    	{
	    		if (upload[gunid] == 0)
	    		{
	    			charge_fault_occur(gunid + 1, DEV_ERR_300D);

	    			op_reason.detail_code = DEV_ERR_300D;
	    			op_reason.reason = 5;
	    			op_reason.gun_id = gunid;
	    			// 设置故障信息
	    			cmd.cmdtype = SET_STOP_DETAIL_REASON;
	    			cmd.body	= (void*)&op_reason;
	    			gt_para_from_main.cmd_fun(&cmd);

	    			upload[gunid] = 1;
	    		}
	    		commFail[gunid] = pmeter->failReadMt;
	    	}
		}
		else
		{
			if ((((yxdata[gunid].yx_dc_pf22[1]>>2)&0x03) == 0) && (upload[gunid] == 1) && (g_can_state[gunid] == 0))
			{
				charge_fault_recover(gunid + 1);
				upload[gunid] = 0;
			}

			fail_cnt[gunid] = 0;
			commFail[gunid] = pmeter->failReadMt;
		}
	}
    return 0;
}
 
